package magnet.processor.instances.aspects.factory;

import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import magnet.processor.instances.*;

public interface CreateMethodGenerator {

    default void visitFactoryClass(FactoryType factoryType) throws IllegalAccessException {}
    default void enterCreateMethod(CreateMethod createMethod) {}
    default void visitCreateMethodParameter(MethodParameter parameter) {}
    default void exitCreateMethod() {}

    void generate(TypeSpec.Builder typeBuilder);

    static void addCreateParameterStatement(CodeBlock.Builder builder, MethodParameter parameter) {

        Expression expression = parameter.getExpression();
        if (expression instanceof Expression.Getter) {
            builder.addStatement(
                    "$T $L = scope." + getterName((Expression.Getter) expression) + "($T.class, $S)",
                    parameter.getReturnType(),
                    parameter.getName(),
                    parameter.getParameterType(),
                    parameter.getClassifier()
            );
        }
        //TODO 不处理kotlin的lazy
//        else if (expression instanceof Expression.LazyGetter) {
//            builder.addStatement(
//                    "$T $L = new $T(" + PARAM_SCOPE_NAME + ", $T.class, $S)",
//                    parameter.getReturnType(),
//                    parameter.getName(),
//                    expression,
//                    parameter.getParameterType(),
//                    parameter.getClassifier()
//            );
//        }
    }

    static MethodSpec.Builder addNewInstanceStatement(MethodSpec.Builder builder, String constructorParameters, CreateStatement createStatement) {
        if (createStatement instanceof TypeCreateStatement) {
            builder.addStatement(
                    "return new $T(" + constructorParameters + ")",
                    ((TypeCreateStatement) createStatement).getInstanceType()
            );
        } else if (createStatement instanceof StaticMethodCreateStatement) {
            builder.addStatement(
                    "return $T.$L(" + constructorParameters + ")",
                    ((StaticMethodCreateStatement) createStatement).getStaticMethodClassName(),
                    ((StaticMethodCreateStatement) createStatement).getStaticMethodName()
            );
        }
        return builder;
    }

    static String getterName(Expression.Getter getter) {
        switch (getter.cardinality) {
            case Single:
                return "getSingle";
            case Optional:
                return "getOptional";
            case Many:
                return "getMany";
        }
        return "";
    }
}
